home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 2
/
Nebula Two.iso
/
SourceCode
/
Multi
/
AppDelegate.m
< prev
next >
Wrap
Text File
|
1995-06-12
|
13KB
|
413 lines
/*----------------------------------------------------------------------------
This file is set up for a width of 130 columns, with tab stops
every two spaces.
HISTORY
10Oct93 DM New
----------------------------------------------------------------------------*/
#import <mach/cthreads.h>
#import "AppDelegate.h"
#import "CircleView.h"
static any_t increasingFunction(self)
AppDelegate *self;
{
/*---------------------------------------------------------------
Simple function that just generates an increasing series
of numbers to display. this runs as an independent
thread; we're forked and detached, then grab a connection to
the main thread,and start sending messages to it.
All four of these functions share some code. It should
probably be factored out into a single method so the line
count can be reduced.
---------------------------------------------------------------*/
id proxy; // "proxy" object to the main server; essentially "self"
int i; // generic int
// Get a connection to the main server. This allows us to be detached,
// yet talk to appkit and the DPS in a thread-safe way.
proxy = [NXConnection connectToName:"fooServer"];
// If we got nothing on the connect attempt, or if the object we got back
// does not speak our "language", then punt.
if((proxy == nil) || (![proxy conformsTo:@protocol(ServerInterface)]))
{
printf("Couldn't get connection to server object, or protocol is hosed\n");
cthread_exit(0);
}
// Loop forever, generating an increasing sequence. We wrap after
// some arbitrarily large number so we don't get overflow.
while(YES)
{
i = 0;
while(i < 128000)
{
[proxy showIncreasing:i]; // Tell the main thread to display this number
i++;
if(!self->isRunning)
cthread_exit(0);
cthread_yield(); // Be polite to the scheduler (not required)
}
}
return 0;
}
static any_t fibFunction(self)
AppDelegate *self;
{
/*------------------------------------------------------------------------
Much like the above. We're running as a thread, and attach to the
DO server and message that. We just generate a series of fib
numbers for display.
------------------------------------------------------------------------*/
id proxy; // Proxy to main server object
int i, j, sum;
// Get connection to main server
proxy = [NXConnection connectToName:"fooServer"];
// If we got nothing on the connect attempt, or if the object we got back
// does not speak our "language", then punt.
if((proxy == nil) || (![proxy conformsTo:@protocol(ServerInterface)]))
{
printf("Couldn't get connection to server object\n");
cthread_exit(0);
}
// Generate new fib numbers forever. Roll over after some arbitrarily
// large number to prevent overflow.
while(YES)
{
i = 0; j = 1; sum = 0;
[proxy showFib:i];
while(i < 128000)
{
sum = i + j;
[proxy showFib:sum];
i = j;
j = sum;
if(!self->isRunning)
cthread_exit(0);
cthread_yield(); // Be polite to the scheduler (not required)
}
}
return 0;
}
static any_t primeFunction(self)
AppDelegate *self;
{
/*------------------------------------------------------------------------
Much like the above. We're running as a thread, and attach to the
DO server and message that. We just generate a series of prime
numbers for display. I have no idea how the algo here works; just
cut & pasted from something else.
------------------------------------------------------------------------*/
id proxy; // Proxy to main server object
int counter, possiblePrime = 5, testLimit;
BOOL isPrime;
List *primeList;
// Get connection to main server
proxy = [NXConnection connectToName:"fooServer"];
// If we got nothing on the connect attempt, or if the object we got back
// does not speak our "language", then punt.
if((proxy == nil) || (![proxy conformsTo:@protocol(ServerInterface)]))
{
printf("Couldn't get connection to server object\n");
cthread_exit(0);
}
// Sleaze alert: Lists are intended to hold ids, pointers to objects. If
// we squint, and don't care a lot about nicities, we can also store ints
// in them. The access is pretty slow, since it takes a function call
// to find the contents of an address. But we could fix that if we liked
// by just doing some pointer arithmetic into the List.
primeList = [[List alloc] init];
[primeList addObject:(id)2];
[primeList addObject:(id)3];
while (YES) // Repeat forever
{
isPrime = YES;
testLimit = sqrt(possiblePrime);
for (counter=1; isPrime && ((int)[primeList objectAt:counter]<=testLimit); counter++)
if (possiblePrime % (int)[primeList objectAt:counter] == 0)
isPrime = NO;
if (isPrime)
{
[primeList addObject:(id)possiblePrime];
[proxy showPrime:possiblePrime];
}
possiblePrime += 2;
if(!self->isRunning)
cthread_exit(0);
cthread_yield(); // Be polite to the scheduler (not required)
if(possiblePrime > 128000) // Begin again to prevent overflow
{
possiblePrime = 5;
[primeList free];
primeList = [[List alloc] init];
[primeList addObject:(id)2];
[primeList addObject:(id)3];
}
}
return 0;
}; // end of primeFunction
static any_t circleFunction(self)
AppDelegate *self;
{
/*------------------------------------------------------------------------
Much like the above. We're running as a thread, and attach to the
DO server and message that. We generate a series of points and
radii, and send those to the main thread server. that draws
the circles.
------------------------------------------------------------------------*/
id proxy; // Proxy to main server object
int maxHeight = 156, maxWidth = 255; // aprox. dimensions of the View
NXPoint center;
float radius;
int x,y,r; // int versions of x, y, radius
// Get connection to main server. Yeah, this common code ought to
// be factored out into its own method. Sue me.
proxy = [NXConnection connectToName:"fooServer"];
// If we got nothing on the connect attempt, or if the object we got back
// does not speak our "language", then punt.
if((proxy == nil) || (![proxy conformsTo:@protocol(ServerInterface)]))
{
printf("Couldn't get connection to server object\n");
cthread_exit(0);
}
// Generate a series of points and radii, and pass them off
// to the main thread for drawing.
srandom(1); // initialize rng
while(YES) // loop forever
{
x = random(); y = random(); r = random();
// Get them scaled back to about the size of the view.
center.x = (float)(((double)x/(double)MAXINT) * (double)maxWidth);
center.y = (float)(((double)y/(double)MAXINT) * (double)maxHeight);
radius = (float)((((double)r/(double)MAXINT)*2.0) * (double)maxHeight);
[proxy drawRandomCircleAt:center withRadius:radius];
if(!self->isRunning)
cthread_exit(0);
cthread_yield(); // Be polite to the scheduler.
}
return 0;
}
@implementation AppDelegate
// The main methods called by the threads, which output things to the screen.
// These are the implementations of the protocol declaration.
- showIncreasing // Show an increasing number in the window
:(int)pNumber; // INPUT: the number to show
{
/*-------------------------------------------------------------------------
Make an addition to the scrolling display of data in the ScrollView
for the "increasing number" display.
-------------------------------------------------------------------------*/
Text *textObj;
char theNumber[256];
sprintf(theNumber, "%d\n", pNumber);
textObj = [increasingDisp docView];
[self addToText:textObj string:theNumber];
return self;
} // end of showIncreasing
- showPrime // Show a prime number in the window
:(int)pPrime; // INPUT: the prime to show
{
/*-------------------------------------------------------------------------
Make an addition to the scrolling display of data in the ScrollView
for the "increasing prime" display.
-------------------------------------------------------------------------*/
Text *textObj;
char theNumber[256];
sprintf(theNumber, "%d\n", pPrime);
textObj = [primeDisp docView];
[self addToText:textObj string:theNumber];
return self;
} // end of showPrime:
- showFib // Show a fibonaci number in the window
:(int)pFib; // INPUT: the fib to show
{
/*-------------------------------------------------------------------------
Make an addition to the scrolling display of data in the ScrollView
for the "increasing fibonacci" display.
-------------------------------------------------------------------------*/
Text *textObj;
char theNumber[256];
sprintf(theNumber, "%d\n", pFib);
textObj = [fibDisp docView];
[self addToText:textObj string:theNumber];
return self;
} // end of showFib:
- drawRandomCircleAt // Draw a circle at the given point with the given radius
:(NXPoint)pPoint // INPUT: where to draw it at (the center)
withRadius:(float)pRadius; // INPUT: the radius
{
/*-------------------------------------------------------------------------------
Add a circle to the view that displays the random circles. This also adds
a circle to the display list kept in the CircleView, which is probably
overkill. But we will be able to redraw it in its current state anywhere.
-------------------------------------------------------------------------------*/
[circleView addCircleAt:pPoint withRadius:pRadius];
[circleView display];
return self;
}
// App initialization delegate method
- appDidInit:sender;
{
// Vend ourselves to the universe (and our threads, too.)
// This is run from the appkit; the idea is to allow anyone
// to call us, and we handle all talking to the appkit.
[NXConnection setDefaultTimeout:200000]; // Timeout period, in milliseconds
connection = [NXConnection registerRoot:self withName:"fooServer"];
[connection runFromAppKit];
return self;
}
- doThreads:sender; // Starts doing things--slamming numbers to the screen
{
/*---------------------------------------------------------------
Do some stuff. Namely, start the threads that display
things to the screen. We have functions that do nothing
but generate output; they message us via distributed objects
and tell us what to display, and we do it.
---------------------------------------------------------------*/
// Clear out any existing cruft in the views.
[circleView emptyCircles];
[circleView display];
[[increasingDisp docView] selectAll:self];
[[increasingDisp docView] delete:self];
[[fibDisp docView] selectAll:self];
[[fibDisp docView] delete:self];
[[primeDisp docView] selectAll:self];
[[primeDisp docView] delete:self];
// Break off all the threads for the stuff we want to do-- draw circles,
// calculate primes, whatever.
// "I woke up this morning with a bad hangover, and my cthread was
// missing. This happens all the time. It's detachable."
// -- Not King Missile
isRunning = YES;
cthread_detach(cthread_fork(increasingFunction, self));
cthread_detach(cthread_fork(fibFunction, self));
cthread_detach(cthread_fork(primeFunction, self));
cthread_detach(cthread_fork(circleFunction, self));
return self;
}
- stopThreads:sender; // Stops all the treads
{
/*-----------------------------------------------------------------------
Stops all the threads, while leaving the display as is.
-----------------------------------------------------------------------*/
isRunning = NO;
return self;
}
- addToText // Utility method--adds text at end of given text obj
:(Text*)pTextObj // INPUT: text obj to add to
string:(char*)pString; // INPUT: the text we're adding
{
/*------------------------------------------------------------------------------
This would be better implemented as a category method to the Text object,
but that would probably just confuse things for the rookies out there.
We have very similar code in three of our functions, that just add
a number to the end of a scrolling text display. This does that, given
the text object passed in and the text to append.
If we _did_ use a category method, everyone could use this method, which
is pretty useful.
------------------------------------------------------------------------------*/
int length; // How many chars are in the text object
length = [pTextObj textLength]; // find out how long...
[pTextObj setSel:length :length]; // get a null selection at the end...
[pTextObj replaceSel:pString]; // and replace it with our new text
[pTextObj scrollSelToVisible]; // make sure we can see it.
return self;
}
@end